﻿﻿//--------------------------------------------------------------------------------------------------
// <author>Rob Gillen</author>
// <authorEmail>gillenre@ornl.gov</authorEmail>
// <remarks>
//   This program builds a collection of data files to be used for testing
// </remarks>
// <copyright file="Program.cs" company="Oak Ridge National Laboratory">
//   Copyright (c) 2010 Oak Ridge National Laboratory, unless otherwise noted.  
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU Lesser General Public License as published by
//   the Free Software Foundation; either version 3 of the License, or
//   (at your option) any later version.
//
//   NOTE: this program is dependent on the Command Line Parser Library which is
//   Copyright (c) 2005 - 2009 Giacomo Stelluti Scala and licensed under the MIT license.
//   The code and library are available here: http://commandline.codeplex.com
//   and the license is viewable here: http://commandline.codeplex.com/license
//
//   This program is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU Lesser General Public License for more details.
//
//   You should have received a copy of the GNU Lesser General Public License
//   along with this program; if not, write to the Free Software
//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//   The license is also available at:
//      http://www.gnu.org/copyleft/lgpl.html
//
// </copyright>
//--------------------------------------------------------------------------------------------------


namespace RRSync.FileGenerator
{
    using System;
    using System.IO;
    using System.Security.Cryptography;

    /// <summary>
    /// Simple application to generate random data files for transfer testing
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Entry point for application
        /// </summary>
        /// <param name="args">Collection of command line arguments</param>
        /// <returns>Value indicating the success of the operation.</returns>
        [STAThread]
        public static int Main(string[] args)
        {
            // make folder structure
            Directory.CreateDirectory("Data");

            GenerateRandomFiles("Data", "Sync", 5, 1 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 5, 2 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 4, 3 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 4, 4 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 3, 5 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 3, 6 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 2, 7 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 2, 8 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 2, 9 * 1024 * 1024, 1);
            GenerateRandomFiles("Data", "Sync", 2, 10 * 1024 * 1024, 1);

            // File 512KB
            //GenerateRandomFiles("Data", "Sync", 1000, 512 * 1024, 1);

            // File 1MB
            //GenerateRandomFiles("Data", "Sync", 8000, 1 * 1024 * 1024, 1);

            // File 1.5MB
            //GenerateRandomFiles("Data", "Sync", 10000, (long)1.5 * 1024 * 1024, 1);

            // File 2MB
            //GenerateRandomFiles("Data", "Sync", 5, 2 * 1024 * 1024, 1);

            // File 5MB
            //GenerateRandomFiles("Data", "Sync", 5, 5 * 1024 * 1024, 1);

            // File 25MB
            //GenerateRandomFiles("Data", "Sync", 10, 25 * 1024 * 1024, 1);


            // create 2KB files
            //GenerateRandomFiles("Data", "2KB", 50, 2048, 1);
            //GenerateRandomFiles("Data", "32KB", 50, 32768, 1);
            //GenerateRandomFiles("Data", "64KB", 50, 65536, 1);
            //GenerateRandomFiles("Data", "128KB", 50, 131072, 1);
            //GenerateRandomFiles("Data", "256KB", 50, 262144, 1);
            //GenerateRandomFiles("Data", "512KB", 50, 524288, 1);
            //GenerateRandomFiles("Data", "1MB", 50, 1048576, 1);
            //GenerateRandomFiles("Data", "5MB", 50, 5242880, 1);
            //GenerateRandomFiles("Data", "10MB", 50, 10485760, 1);
            //GenerateRandomFiles("Data", "25MB", 50, 26214400, 1);
            //GenerateRandomFiles("Data", "50MB", 50, 52428800, 1);
            //GenerateRandomFiles("Data", "100MB", 50, 104857600, 1);

            // NOTE, you may get some out of memory errors on this... still tracking this down
            // doesn't happen every time... (my box as 8GB)
            //GenerateRandomFiles("Data", "250MB", 50, 262144000, 1);
            //GenerateRandomFiles("Data", "500MB", 50, 104857600, 5);
            //GenerateRandomFiles("Data", "750MB", 50, 262144000, 3);
            //GenerateRandomFiles("Data", "1GB", 50, 104857600, 10);

            return 0;
        }

        /// <summary>
        /// Generates a collection of random files filled with random data
        /// </summary>
        /// <param name="rootPath">Root path into which the data should be stuffed</param>
        /// <param name="folderName">A folder name (relative to rootPath) into which the data files should be placed</param>
        /// <param name="fileCount">Number of files to create</param>
        /// <param name="numBytes">Number of bytes in a single stack to create</param>
        /// <param name="stackCount">Number of times the numBytes stack should be repeated within the file</param>
        /// <remarks>
        /// As the number of bytes gets larger, the random data generator hits memory issues. Therefore, the stackCount
        /// parameter was added allowing you to generate smaller arrays of random data that is then duplicated stackCount
        /// times in the file, allowing you to still achieve large file sizes.
        /// </remarks>
        private static void GenerateRandomFiles(string rootPath, string folderName, int fileCount, long numBytes, int stackCount)
        {
            Console.WriteLine("Generating Files for {0}", folderName);

            // create the directory
            Directory.CreateDirectory(Path.Combine(rootPath, folderName));

            // generate the files
            for (int i = 0; i < fileCount; i++)
            {
                // generate random filename
                string fileName = Path.Combine(Path.Combine(rootPath, folderName), Path.GetRandomFileName());

                // get the randomized data
                byte[] randomData = GetRandomBytes(numBytes);

                // create the file
                using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
                {
                    // Create the writer for data.
                    BinaryWriter w = new BinaryWriter(fs);

                    // Write data to the file
                    for (long j = 0; j < stackCount; j++)
                    {
                        w.Write(randomData);
                    }

                    w.Close();
                }

                // this kept throwing an out of memory error when numBytes
                // hit 750MB - probably a int to long issue
                // File.WriteAllBytes(fileName, GetRandomBytes(numBytes));
            }
        }

        /// <summary>
        /// Gets a random collection of data of length bytes
        /// </summary>
        /// <param name="bytes">Number of random bytes to generate</param>
        /// <returns>An array of length bytes full of random data</returns>
        private static byte[] GetRandomBytes(long bytes)
        {
            // Create a byte array to hold the random value.
            byte[] randomBytes = new byte[bytes];

            // Create a new instance of the RNGCryptoServiceProvider.
            RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider();

            // Fill the array with a random value.
            generator.GetBytes(randomBytes);

            return randomBytes;
        }
    }
}
